//
// Created by xu on 2024/11/15.
//
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <pthread.h>

#ifdef _WIN32
#define FMT_NAME "dshow"
#define DEVICE_NAME "audio=耳机 (EDIFIER Lolli Pro 2 Hands-Free)"
#define FILENAME "D:/out.pcm"
#else
#define FMT_NAME "avfoundation"
#define DEVICE_NAME ":0"
#define FILENAME "/Users/songdongxu/Desktop/out.pcm"
#endif

void *record_audio(void *arg) {
    FILE *f;
    AVPacket *pkt;
    AVFormatContext *ctx = NULL;
    int count = 2;
    int ret;
    // 强制转换
    ctx = (AVFormatContext *) arg;
    // 文件
    f = fopen(FILENAME, "wb");
    if (f < 0) {
        av_log(NULL, AV_LOG_INFO, "打开文件失败\n");
        goto exit;
    }

    pkt = av_packet_alloc();
    while (count-- > 0) {
        // 从设备中采集数据
        ret = av_read_frame(ctx, pkt);
        if (ret == 0) {
            // 将数据写入
            fwrite(pkt->data, 1, pkt->size, f);
            // 释放资源
            av_packet_unref(pkt);
        } else if (ret == AVERROR(EAGAIN)) {
            continue;
        } else {
            char errbuf[1024] = {0};
            av_strerror(ret, errbuf, sizeof(errbuf));
            av_log(NULL, AV_LOG_ERROR, "采集数据失败%s\n", errbuf);
            break;
        }
    }

    exit:
    // 关闭文件
    fclose(f);
    // 释放资源
    av_packet_free(&pkt);
    return 0;
}


int main(int argc, char *argv[]) {
    pthread_t pthread;
    AVFormatContext *ctx = NULL;
    const AVInputFormat *fmt;
    int ret;

    // 注册设备
    avdevice_register_all();
    // 根据格式名称获取输入格式对象
    fmt = av_find_input_format(FMT_NAME);
    if (!fmt) {
        av_log(NULL, AV_LOG_INFO, "找不到输入格式%s\n", FMT_NAME);
        return -1;
    }
    // 打开设备
    ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, NULL);
    if (ret < 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf));
        av_log(NULL, AV_LOG_ERROR, "打开设备失败%s\n", errbuf);
        return ret;
    }

    // 创建线程
    ret = pthread_create(&pthread, NULL, record_audio, ctx);
    if (ret) {
        av_log(NULL, AV_LOG_INFO, "线程创建失败\n");
        goto exit;
    }
    // 线程join
    ret = pthread_join(pthread, NULL);
    if (ret) {
        av_log(NULL, AV_LOG_INFO, "线程Join失败\n");
    }
    exit:
    // 关闭设备
    avformat_close_input(&ctx);
    return 0;
}